﻿//-----------------------------------------------------------------------------------------------------------
// Wbfs Engine (WBFSe) Project by Omega Frost 
// http://wbfse.codeplex.com/
//
// WBFSe is Licensed under the terms of the 
// Microsoft Reciprocal License (Ms-RL)
//-----------------------------------------------------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace WBFSe.IO
{
    /// <summary>
    /// Represents memory in the unmanaged memory domain
    /// </summary>
    public class UnmanagedArray : IDisposable
    {
        private static int allocated;

        // Variables

        IntPtr dataPtr;
        int size;

        // Properties

        /// <summary>
        /// The ammount of allocated unmanaged memory
        /// </summary>
        public static int Allocated
        {
            get { return allocated; }
        }

        /// <summary>
        /// Memory location
        /// </summary>
        public IntPtr DataPtr
        {
            get { return this.dataPtr; }
        }

        /// <summary>
        /// Memory size
        /// </summary>
        public int Size
        {
            get { return this.size; }
        }

        // Methods

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="size">Memory block size</param>
        public UnmanagedArray(int size)
        {
            this.dataPtr = Marshal.AllocHGlobal(size);
            this.size = size;

            Interlocked.Add(ref allocated, size);
        }

        /// <summary>
        /// Copies data from unmanaged memory to managed
        /// </summary>
        public void CopyTo(Byte[] data)
        {
            Marshal.Copy(this.dataPtr, data, 0, this.size);
        }

        /// <summary>
        /// Copies data from unmanaged memory to managed
        /// </summary>
        /// <param name="data">Destination array</param>
        /// <param name="position">Position in unmanaged array</param>
        /// <param name="size">Length to copy</param>
        public void CopyTo(Byte[] data, int position, int size)
        {
            Marshal.Copy(this.dataPtr, data, position, size);
        }

        /// <summary>
        /// Copies data from managed memory to unmanaged
        /// </summary>
        public void CopyFrom(Byte[] data)
        {
            Marshal.Copy(data, 0, this.dataPtr, this.size);
        }

        /// <summary>
        /// Copies data from managed memory to unmanaged
        /// </summary>
        /// <param name="data">Source array</param>
        /// <param name="offset">Offset in source array to copy</param>
        /// <param name="position">Position in unmanaged array</param>
        /// <param name="size">Length to copy</param>
        public void CopyFrom(Byte[] data, int offset, int position, int size)
        {
            Marshal.Copy(data, offset, IntPtr.Add(this.dataPtr, position), size);
        }

        /// <summary>
        /// Frees the memory
        /// </summary>
        public void Dispose()
        {
            if (this.dataPtr != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(this.dataPtr);
                this.dataPtr = IntPtr.Zero;

                Interlocked.Add(ref allocated, -this.size);
            }
        }
    }
}
